using LoanPrequalificationSystem.Model.Borrowers;
using LoanPrequalificationSystem.Model.LoanApplications;


namespace LoanPrequalificationSystem.Model.Products
{
    public class ProductIsAvailableSpecification
    {
        private Product _product;
        private LoanMonthlyPaymentCalculator _loanMonthlyPaymentCalculator;

        public ProductIsAvailableSpecification(Product product, LoanMonthlyPaymentCalculator loanMonthlyPaymentCalculator)
        {
            _product = product;
            _loanMonthlyPaymentCalculator = loanMonthlyPaymentCalculator;
        }

        public bool IsSatisfiedBy(LoanApplication loanApplication)
        {
            bool PreQualifiesForProduct = true;

            if (!IsValidLoanAmount(loanApplication.LoanAmount))
                PreQualifiesForProduct = false;

            if (!PropertyValueGreaterThanLoan(loanApplication.LoanAmount, loanApplication.PropertyValue))
                PreQualifiesForProduct = false;

            if (!LoanWillCoverPropertyValue(loanApplication.LoanAmount, loanApplication.PropertyValue, loanApplication.Deposit))
                PreQualifiesForProduct = false;

            if (!WithMaximumLTV(loanApplication.LoanAmount, loanApplication.Deposit))
                PreQualifiesForProduct = false;

            foreach (var borrower in loanApplication.Borrowers)
            {
                if (!WillPayLoanOffBeforeRetirement(borrower.Age, loanApplication.LoanTerm))
                {
                    PreQualifiesForProduct = false;
                }
            }

            foreach (var borrower in loanApplication.Borrowers)
            {
                if (!HasGoodEnoughCreditScore(borrower.CreditScore.Score))
                {
                    PreQualifiesForProduct = false;
                }
            }

            if (!IsAffordable(loanApplication.LoanAmount, loanApplication.LoanTerm, loanApplication.BorrowerTotalMonthlyIncome(), loanApplication.BorrowerTotalMonthlyDebts()))
                PreQualifiesForProduct = false;

            return PreQualifiesForProduct;
        }


        private bool HasGoodEnoughCreditScore(int creditScore)
        {
            return creditScore > 650;
        }

        private bool WillPayLoanOffBeforeRetirement(int loanAmount, int propertyValue)
        {
            return propertyValue > loanAmount;
        }

        private bool IsAffordable(float loan, int term, float borrowMonthlyIncome, float borrowMonthlyDebt)
        {
            float totalMonthlyDebt = TotalMonthlyDebtWithLoanPaymentFor(loan, term, borrowMonthlyDebt);

            return MonthlyDebtExceedsThirtyPC(borrowMonthlyIncome, totalMonthlyDebt);
        }

        private bool MonthlyDebtExceedsThirtyPC(float borrowMonthlyIncome, float totalMonthlyDebt)
        {
            decimal percentageOfIncomeSpentOnDebt =
                (decimal.Divide((decimal)totalMonthlyDebt, (decimal)borrowMonthlyIncome) * 100);
            return percentageOfIncomeSpentOnDebt < 31;
        }

        private float TotalMonthlyDebtWithLoanPaymentFor(float loan, int term, float borrowMonthlyDebt)
        {
            return _loanMonthlyPaymentCalculator.LoanPaymentsPerMonthFor(loan, _product.InterestRate, term) +
                   borrowMonthlyDebt;
        }


        private bool WithMaximumLTV(float loanAmount,float  deposit)
        {
            return _product.MaximumLTV >= (int) (100*(1 - deposit/(loanAmount + deposit)));
        }

        private bool LoanWillCoverPropertyValue(float loan, float propertValue, float deposit)
        {
            return loan >= (propertValue - deposit);
        }

        private bool PropertyValueGreaterThanLoan(int loanAmount,int propertyValue)
        {
            return propertyValue > loanAmount;
        }

        private bool IsValidLoanAmount(float  loanAmount)
        {
            return loanAmount <= _product.MaximumLoan;
        }
    }
}